package cd.zhixuan.utils.ui;

import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.widget.ImageView;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.constraintlayout.widget.ConstraintLayout;
import androidx.constraintlayout.widget.ConstraintSet;
import androidx.constraintlayout.widget.Constraints;

import cd.zhixuan.utils.LogTools;
import cd.zhixuan.utils.R;

/**
 * 自定义进度条拖拽效果
 *
 * @author HuZhiChao
 * Create Time: 2022.02.10
 **/
public abstract class ISeekBar extends ConstraintLayout {

    private final ImageView progressBgView;
    private final ImageView progressView;
    private final ImageView indicateView;
    private final ConstraintSet constraintSet = new ConstraintSet();
    private int min = 0;
    private int max = 100;
    private int progress = 0;
    private int lastProgress = Integer.MIN_VALUE;
    @Nullable
    private OnProgressListener onProgressListener;
    /**
     * 方向，true：水平，false：垂直
     */
    public final boolean HORIZONTAL;

    public ISeekBar(Context context) {
        this(context, null);
    }

    public ISeekBar(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public ISeekBar(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        setClipToPadding(false);

        //xml参数
        final TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.ISeekBar);
        HORIZONTAL = typedArray.getBoolean(R.styleable.ISeekBar_horizontal, true);
        typedArray.recycle();

        constraintSet.clone(this);
        //进度条背景
        final ImageView pbgView = new ImageView(getContext());
        pbgView.setId(R.id.iseekbar_progress_bg);
        final Constraints.LayoutParams progressBgLp = new Constraints.LayoutParams(0, 0);
        pbgView.setLayoutParams(progressBgLp);
        addView(pbgView);
        progressBgView = pbgView;
        //进度条
        final ImageView pView = new ImageView(getContext());
        pView.setId(R.id.iseekbar_progress);
        final Constraints.LayoutParams progressLp = new Constraints.LayoutParams(0, 0);
        pView.setLayoutParams(progressLp);
        addView(pView);
        progressView = pView;
        //指示器
        final ImageView iView = new ImageView(getContext());
        iView.setId(R.id.iseekbar_indicate);
        final Constraints.LayoutParams indicateLp = new Constraints.LayoutParams(0, 0);
        iView.setLayoutParams(indicateLp);
        addView(iView);
        indicateView = iView;

        //进度条背景
        constraintSet.connect(pbgView.getId(), ConstraintSet.LEFT, ConstraintSet.PARENT_ID, ConstraintSet.LEFT);
        constraintSet.connect(pbgView.getId(), ConstraintSet.RIGHT, ConstraintSet.PARENT_ID, ConstraintSet.RIGHT);
        constraintSet.connect(pbgView.getId(), ConstraintSet.TOP, ConstraintSet.PARENT_ID, ConstraintSet.TOP);
        constraintSet.connect(pbgView.getId(), ConstraintSet.BOTTOM, ConstraintSet.PARENT_ID, ConstraintSet.BOTTOM);
        if (HORIZONTAL) {
            //进度条
            constraintSet.connect(pView.getId(), ConstraintSet.LEFT, pbgView.getId(), ConstraintSet.LEFT);
            constraintSet.connect(pView.getId(), ConstraintSet.TOP, pbgView.getId(), ConstraintSet.TOP);
            constraintSet.connect(pView.getId(), ConstraintSet.BOTTOM, pbgView.getId(), ConstraintSet.BOTTOM);
//            constraintSet.setHorizontalBias(pView.getId(), 0);
            //指示器
            constraintSet.connect(iView.getId(), ConstraintSet.LEFT, pbgView.getId(), ConstraintSet.LEFT);
            constraintSet.connect(iView.getId(), ConstraintSet.TOP, pView.getId(), ConstraintSet.TOP);
            constraintSet.connect(iView.getId(), ConstraintSet.BOTTOM, pView.getId(), ConstraintSet.BOTTOM);
//            constraintSet.setVerticalBias(iView.getId(), 0f);
        } else {
            //进度条
            constraintSet.connect(pView.getId(), ConstraintSet.LEFT, pbgView.getId(), ConstraintSet.LEFT);
            constraintSet.connect(pView.getId(), ConstraintSet.RIGHT, pbgView.getId(), ConstraintSet.RIGHT);
            constraintSet.connect(pView.getId(), ConstraintSet.BOTTOM, pbgView.getId(), ConstraintSet.BOTTOM);
//            constraintSet.setVerticalBias(pView.getId(), 1);
            //指示器
            constraintSet.connect(iView.getId(), ConstraintSet.LEFT, pView.getId(), ConstraintSet.LEFT);
            constraintSet.connect(iView.getId(), ConstraintSet.RIGHT, pView.getId(), ConstraintSet.RIGHT);
            constraintSet.connect(iView.getId(), ConstraintSet.BOTTOM, pbgView.getId(), ConstraintSet.BOTTOM);
//            constraintSet.setVerticalBias(iView.getId(), 1);
        }

        setupProgressBackgroundView(pbgView, progressBgLp, constraintSet);//
        setupProgressView(pView, progressLp, constraintSet);//
        setupIndicateView(iView, indicateLp, constraintSet);//

        constraintSet.applyTo(this);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        //留出指示器宽度
        if (HORIZONTAL) {
            int left = indicateView.getMeasuredWidth() / 2 + indicateView.getPaddingLeft();
            int right = indicateView.getMeasuredWidth() / 2 + indicateView.getPaddingRight();
            setPadding(left, 0, right, 0);
        } else {
            int top = indicateView.getMeasuredHeight() / 2 + indicateView.getPaddingTop();
            int bot = indicateView.getMeasuredHeight() / 2 + indicateView.getPaddingBottom();
            setPadding(0, top, 0, bot);
        }
//        updateProgress();
    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        super.onLayout(changed, left, top, right, bottom);
        LogTools.d("changed=" + changed + "\nleft=" + left + "\ntop=" + top + "\nright=" + right + "\nbottom=" + bottom);
    }

    /**
     * 进度条背景设置
     */
    public abstract void setupProgressBackgroundView(@NonNull ImageView view, @NonNull Constraints.LayoutParams lp, @NonNull ConstraintSet set);

    /**
     * 进度条设置
     */
    public abstract void setupProgressView(@NonNull ImageView view, @NonNull Constraints.LayoutParams lp, @NonNull ConstraintSet set);

    /**
     * 指示器设置
     */
    public abstract void setupIndicateView(@NonNull ImageView view, @NonNull Constraints.LayoutParams lp, @NonNull ConstraintSet set);

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                if (onProgressListener != null) {
                    onProgressListener.handStart();
                }
            case MotionEvent.ACTION_MOVE:
                final float fingerOffset;
                final int dis;
                if (HORIZONTAL) {
                    dis = getMeasuredWidth() - getPaddingLeft() - getPaddingRight();
                    fingerOffset = event.getX() - getPaddingLeft();
                } else {
                    dis = getMeasuredHeight() - getPaddingTop() - getPaddingBottom();
                    fingerOffset = dis - (event.getY() - getPaddingTop());
                }
                int p = min + (int) ((max - min) * fingerOffset / dis);
                if (p < min) {
                    p = min;
                } else if (p > max) {
                    p = max;
                }
                progress = p;
//                LogTools.d(event.getAction()+" : "+progress);
                updateProgress(true);
                return true;
            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_CANCEL:
                if (onProgressListener != null) {
                    onProgressListener.handFinished();
                }
                break;
        }
        return super.onTouchEvent(event);
    }

    public void updateProgress() {
        post(updateProgress);
    }

    private final Runnable updateProgress = () -> updateProgress(false);

    private void updateProgress(boolean byHand) {

        final int maxx = max - min;
        final int proxx = progress - min;
        float scale = 1f * proxx / maxx;
        if (scale < 0) {
            scale = 0;
        } else if (scale > 1) {
            scale = 1;
        }
        LogTools.d("max=" + max + " , min=" + min + " , progress=" + progress + " , scale=" + scale);
        float indicateX, indicateY;//指示器坐标

        final ConstraintLayout.LayoutParams progressLp = (LayoutParams) progressView.getLayoutParams();
        if (HORIZONTAL) {
            float width = progressBgView.getMeasuredWidth();
            width = width * scale;
            progressLp.width = (int) width;
            indicateX = progressView.getX() + width;
            indicateY = progressView.getY() + progressView.getMeasuredHeight() / 2f;
        } else {
            float height = progressBgView.getMeasuredHeight();
            height = height * scale;
            progressLp.height = (int) height;
            indicateX = progressView.getX() + progressView.getMeasuredWidth() / 2f;
            indicateY = progressView.getY() + progressView.getMeasuredHeight() - height;
        }
        progressView.setLayoutParams(progressLp);

        indicateView.setX(indicateX - indicateView.getMeasuredWidth() / 2f);
        indicateView.setY(indicateY - indicateView.getMeasuredHeight() / 2f);

        final int last = this.lastProgress;
        this.lastProgress = progress;
        if (onProgressListener != null && last != progress) {
            onProgressListener.progress(last, progress, byHand);
        }
    }

    public void setMin(int min) {
        this.min = min;
    }

    public void setMax(int max) {
        this.max = max;
    }

    public void setProgress(int progress) {
        this.progress = progress;
        this.lastProgress = Integer.MIN_VALUE;
    }

    public void setOnProgressListener(@Nullable OnProgressListener l) {
        this.onProgressListener = l;
    }

    public interface OnProgressListener {
        void handStart();//开始手动change

        void handFinished();//手动change完成

        void progress(int lastProgress, int curProgress, boolean byHand);
    }

    public int getMin() {
        return min;
    }

    public int getMax() {
        return max;
    }

    public int getProgress() {
        return progress;
    }
}
